package com.gckj.dfds.backup;

import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 负责管理内存中的文件目录树的核心组件
 *
 * @author zhonghuashishan
 */
public class FSDirectory {

    /**
     * 内存中的文件目录树
     */
    private INode dirTree;

    /**
     * 当前内存中最大的txid
     */
    private Long maxTxid = 0L;

    private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public void readLock() {
        readWriteLock.readLock().lock();
    }

    public void unReadLock() {
        readWriteLock.readLock().unlock();
    }

    public void writeLock() {
        readWriteLock.writeLock().lock();
    }

    public void unWriteLock() {
        readWriteLock.writeLock().unlock();
    }

    public FSDirectory() {
        this.dirTree = new INode("/",0);
    }

    public FsImage getFsImage(){
        try {
            readLock();
            String fsImageJson = JSONObject.toJSONString(dirTree);
            FsImage fsImage = new FsImage(maxTxid, fsImageJson);
            return fsImage;
        } finally {
            unReadLock();
        }
    }


    public INode getDirTree() {
        return dirTree;
    }

    public void setDirTree(INode dirTree) {
        this.dirTree = dirTree;
    }

    /**
     * 创建目录
     *
     * @param path 目录路径
     */
    public void mkdir(Long txid, String path) {
        try {
            writeLock();
            maxTxid = txid;
            String[] pathes = path.split("/");
            INode parent = dirTree;
            for (String splitedPath : pathes) {
                if (splitedPath.trim().equals("")) {
                    continue;
                }
                INode dir = findDirectory(parent, splitedPath);
                if (dir != null) {
                    parent = dir;
                    continue;
                }
                INode child = new INode(splitedPath,0);
                parent.addChild(child);
                parent = child;
            }
        } finally {
            unWriteLock();
        }

        // printDirTree();
    }

    private void getChild(String dirPath, List<INode> children, List<String> dirList) {
        if (children.isEmpty()) {
            dirList.add(dirPath);
            return;
        }
        for (INode child : children) {
            INode childDir = (INode) child;
            dirPath = dirPath + "/" + childDir.getPath();
            getChild(dirPath, childDir.getChildren(), dirList);
        }

    }

    /**
     * 对文件目录树递归查找目录
     *
     * @param dir
     * @param path
     * @return
     */
    private INode findDirectory(INode dir, String path) {
        if (dir.getChildren().size() == 0) {
            return null;
        }

        for (INode child : dir.getChildren()) {
            if (child instanceof INode) {
                INode childDir = (INode) child;

                if ((childDir.getPath().equals(path))) {
                    return childDir;
                }

            }
        }
        return null;
    }


    public INode findParent(String path) {
        String[] split = path.split("/");
        INode parent = dirTree;
        for (String s : split) {
            if("".equals(s.trim())) {
                continue;
            }
            INode dir = findDirectory(parent, s);
            if (dir != null) {
                parent = dir;
                continue;
            }
            INode child = new INode(s,0);
            parent.addChild(child);
            parent = child;
        }
        return parent;
    }

    public void createFile(Long txid, String path){
        try {
            writeLock();
            maxTxid = txid;
            String parentPath = path.substring(0, path.lastIndexOf("/"));
            String fileName = path.substring(path.lastIndexOf("/") + 1);
            INode parent = this.findParent(parentPath);
            List<INode> children = parent.getChildren();
            INode child = new INode(fileName, 1);
            parent.addChild(child);
        } finally {
            unWriteLock();
        }
    }


}
